# frozen_string_literal: true

require 'optparse'

module RubyCritic
  module Cli
    class Options
      # rubocop:disable Metrics/ClassLength
      class Argv
        def initialize(argv)
          @argv = argv
          self.parser = OptionParser.new
        end

        # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
        def parse
          parser.new do |opts|
            opts.banner = 'Usage: rubycritic [options] [paths]'

            opts.on('-p', '--path [PATH]', 'Set path where report will be saved (tmp/rubycritic by default)') do |path|
              @root = path
            end

            opts.on('-b', '--branch BRANCH', 'Set branch to compare') do |branch|
              self.base_branch = String(branch)
              set_current_branch
              self.mode = :compare_branches
            end

            opts.on(
              '-t',
              '--maximum-decrease [MAX_DECREASE]',
              'Set a threshold for score difference between two branches (works only with -b)'
            ) do |threshold_score|
              self.threshold_score = Integer(threshold_score)
            end

            formats = []
            self.formats = formats
            opts.on(
              '-f', '--format [FORMAT]',
              %i[html json console lint],
              'Report smells in the given format:',
              '  html (default; will open in a browser)',
              '  json',
              '  console',
              '  lint',
              'Multiple formats are supported.'
            ) do |format|
              formats << format
            end

            formatters = []
            self.formatters = formatters
            opts.on(
              '--custom-format [REQUIREPATH]:[CLASSNAME]|[CLASSNAME]',
              'Instantiate a given class as formatter and call report for reporting.',
              'Two ways are possible to load the formatter.',
              'If the class is not autorequired the REQUIREPATH can be given together',
              'with the CLASSNAME to be loaded separated by a :.',
              'Example: rubycritic/markdown/reporter.rb:RubyCritic::MarkDown::Reporter',
              'or if the file is already required the CLASSNAME is enough',
              'Example: RubyCritic::MarkDown::Reporter',
              'Multiple formatters are supported.'
            ) do |formatter|
              formatters << formatter
            end

            opts.on('-s', '--minimum-score [MIN_SCORE]', 'Set a minimum score') do |min_score|
              self.minimum_score = Float(min_score)
            end

            opts.on('--churn-after [DATE]', 'Only count churn from a certain date.',
                    'The date is passed through to version control (currently git only).',
                    'Example: 2017-01-01') do |churn_after|
              self.churn_after = churn_after
            end

            opts.on('-m', '--mode-ci [BASE_BRANCH]',
                    'Use CI mode (faster, analyses diffs w.r.t base_branch (default: main))') do |branch|
              self.base_branch = branch || 'main'
              set_current_branch
              self.mode = :ci
            end

            opts.on('--deduplicate-symlinks', 'De-duplicate symlinks based on their final target') do
              self.deduplicate_symlinks = true
            end

            opts.on('--suppress-ratings', 'Suppress letter ratings') do
              self.suppress_ratings = true
            end

            opts.on('--no-browser', 'Do not open html report with browser') do
              self.no_browser = true
            end

            opts.on('--coverage-path [PATH]', 'SimpleCov coverage will be saved (./coverage by default)') do |path|
              @coverage_path = path
            end

            opts.on_tail('-v', '--version', "Show gem's version") do
              self.mode = :version
            end

            opts.on_tail('-h', '--help', 'Show this message') do
              self.mode = :help
            end
          end.parse!(@argv)
        end

        def to_h
          {
            mode: mode,
            root: root,
            formats: formats,
            formatters: formatters,
            deduplicate_symlinks: deduplicate_symlinks,
            paths: paths,
            suppress_ratings: suppress_ratings,
            help_text: parser.help,
            minimum_score: minimum_score,
            churn_after: churn_after,
            no_browser: no_browser,
            base_branch: base_branch,
            feature_branch: feature_branch,
            threshold_score: threshold_score
          }
        end
        # rubocop:enable Metrics/MethodLength,Metrics/AbcSize

        private

        attr_accessor :mode, :root, :formats, :formatters, :deduplicate_symlinks,
                      :suppress_ratings, :minimum_score, :churn_after, :no_browser,
                      :parser, :base_branch, :feature_branch, :threshold_score, :coverage_path

        def paths
          @argv unless @argv.empty?
        end

        def set_current_branch
          self.feature_branch = SourceControlSystem::Git.current_branch
        end
      end
      # rubocop:enable Metrics/ClassLength
    end
  end
end
